package com.csc775.gui;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import java.util.StringTokenizer;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;

import com.csc775.AndroidWalkieTalkieActivity;
import com.csc775.R;
import com.csc775.message.ControlMessage;
import com.csc775.message.ControlRquestType;
import com.csc775.networking.Client;

public class TalkActivity extends Activity {

	private static boolean isButtonClick = false;
	static DatagramSocket socket = null;
	private AudioRecord recorder = null;
	private int bufferSize = 16000;
	private Thread recordingThread = null;
	private boolean isRecording = false;
	private HashMap<String, Integer> memInfo = null;
	private Button btnStop, btnTalk, btnHand, btnSignout;
	private static ToggleButton btnTog;
	private static Context context = null;
	private static int serverPort = 12345;
	// messages to show as a Toast
	Toast toastListen = null;
	Toast toastNoPeer = null, toastWantToTalk = null;
	private boolean isListening = false;
	private Client c = null;

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		super.onKeyDown(keyCode, event);
		switch (keyCode) {
		
		case KeyEvent.KEYCODE_CAMERA:
			if (!isButtonClick) {// is false
				Toast.makeText(TalkActivity.this,
						"Pressed push-to-talk Button", Toast.LENGTH_SHORT)
						.show();
				ControlMessage msg = new ControlMessage(
						AndroidWalkieTalkieActivity.serverIP,
						AndroidWalkieTalkieActivity.serverPort,
						AndroidWalkieTalkieActivity.currentUserName.length(),
						AndroidWalkieTalkieActivity.currentUserName);
				msg.setRequestType(ControlRquestType.REQUEST_TO_TALK);
				c.Sendmessage(msg.toString());
				isButtonClick = true;
				return true;
			} else {
				Toast.makeText(TalkActivity.this, "Stopped Talking",
						Toast.LENGTH_SHORT).show();
				stopRecording();
				isButtonClick = false;
				return true;
			}
		case KeyEvent.KEYCODE_BUTTON_X:
			// enableButtons(false);
			stopRecording();

			return true;

		}
		return false;
	}

	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.firstwindow);

		if (AndroidWalkieTalkieActivity.isLonin) {
			c = AndroidWalkieTalkieActivity.getClient();
		} else
			c = LoginActivity.getClient();

		context = getApplicationContext();
		
		TextView tv = (TextView) findViewById(R.id.textView1);
		tv.setText(AndroidWalkieTalkieActivity.currentUserName); /*Display Current Username in the Screen*/
		
		toastListen = Toast.makeText(context, "Please Listen",
				Toast.LENGTH_LONG);
		toastNoPeer = Toast.makeText(context,
				"There are no active user in groups", Toast.LENGTH_LONG);
		toastWantToTalk = Toast.makeText(context, "Other user wants to talk",
				Toast.LENGTH_LONG);
		// / talk if this flag is set to true then
		// listening will start. This flag will be set based on the message
		// received from
		// centralized server for talk and stop talking

		boolean isListen = false; // this will enable talking

		btnHand = (Button) findViewById(R.id.HandButton);
		btnHand.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				ControlMessage msg = new ControlMessage(
						AndroidWalkieTalkieActivity.serverIP,
						AndroidWalkieTalkieActivity.serverPort,
						AndroidWalkieTalkieActivity.currentUserName.length(),
						AndroidWalkieTalkieActivity.currentUserName);
				msg.setRequestType(ControlRquestType.HAND);
				c.Sendmessage(msg.toString());

			}
		});

		btnSignout = (Button) findViewById(R.id.btnSignout);
		btnSignout.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				ControlMessage msg = new ControlMessage(
						AndroidWalkieTalkieActivity.serverIP,
						AndroidWalkieTalkieActivity.serverPort,
						AndroidWalkieTalkieActivity.currentUserName.length(),
						AndroidWalkieTalkieActivity.currentUserName);
				stopRecording();
				msg.setRequestType(ControlRquestType.LEAVE);
				c.Sendmessage(msg.toString());

				// ControlMessage cmd =LoginActivity.getClient().recevMsg();
				// if(cmd.getExtraData().equals("BYE"))
				{
					finish();
					Intent myIntent = new Intent(v.getContext(),
							AndroidWalkieTalkieActivity.class);
					startActivityForResult(myIntent, 0);
				}

			}
		});
		btnTog = (ToggleButton) findViewById(R.id.toggleButton1);
		btnTog.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				// Perform action on clicks
				if (btnTog.isChecked()) {
					Toast.makeText(getApplicationContext(), "Talk",
							Toast.LENGTH_SHORT).show();
					ControlMessage msg = new ControlMessage(
							AndroidWalkieTalkieActivity.serverIP,
							AndroidWalkieTalkieActivity.serverPort,
							AndroidWalkieTalkieActivity.currentUserName
									.length(),
							AndroidWalkieTalkieActivity.currentUserName);
					msg.setRequestType(ControlRquestType.REQUEST_TO_TALK);
					c.Sendmessage(msg.toString());
				} else {
					Toast.makeText(getApplicationContext(), "Listen",
							Toast.LENGTH_SHORT).show();
					stopRecording();
				}
			}
		});
		Thread th = new Thread(new Listen());
		th.start();

	}

	class ThreadUDPServer implements Runnable {

		@Override
		public void run() {
			// TODO Auto-generated method stub
			serverUDPStartup(16000);
		}

	}

	class Listen implements Runnable {

		@Override
		public void run() {
			while (true) {
				// TODO Auto-generated method stub
				ControlMessage msg = c.recevMsg();
				if (msg.getRequestType() == ControlRquestType.REQUEST_TO_LISTEN) {
					// enableButtons(true);
					toastListen.show();
					isListening = true;
					Log.d("Test", "Talk is desabled");

					Thread udpServer = new Thread(new ThreadUDPServer());
					udpServer.start();

				}
				if (msg.getRequestType() == ControlRquestType.REQUEST_TO_TALK_ACK) {
					if (!msg.getExtraData().equals("NO_IP_IN_GROUP")) {
						// get response as the list of group members
						memInfo = new HashMap<String, Integer>();
						StringTokenizer tok = new StringTokenizer(
								msg.getExtraData(), "~");
						while (tok.hasMoreTokens()) {
							String str = tok.nextToken();
							Log.d("Test", "Received ==>" + str);
							memInfo.put(str, serverPort);
						}
						Log.d("Test", "Talk is enabled");
						// create UDP Server socket
						openUDPConnection();
						// start recodring
						// enableButtons(true);

						startRecording();
					} else {
						toastNoPeer.show();
					}
				}
				if (msg.getRequestType() == ControlRquestType.LEAVE) {
					// close the application
					try {
						c.getOis().close();
						c.getOos().close();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					System.exit(1);
				}
				if (msg.getRequestType() == ControlRquestType.CHANNEL_OPEN) {
					toastWantToTalk.setText("User want to talk : "
							+ msg.getExtraData());
					toastWantToTalk.show();
				}
			}
		}

	}

	public static void serverUDPStartup(int bufferSize) {
		// TODO Auto-generated method stub
		Thread t[] = new Thread[3];
		AudioTrack mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
				16000, AudioFormat.CHANNEL_OUT_MONO,
				AudioFormat.ENCODING_PCM_16BIT, 16000, AudioTrack.MODE_STREAM);
		mAudioTrack.play();
		try {
			Log.d("Server", "Server Started");
			DatagramSocket sock = new DatagramSocket(serverPort);
			Log.d("Server", "Socket opened at "
					+ InetAddress.getLocalHost().getHostAddress());
			byte[] voice = new byte[bufferSize];

			while (true) {
				DatagramPacket pack = new DatagramPacket(voice, bufferSize);
				sock.receive(pack);
				Log.d("Server", "recv pack: " + pack.getLength());
				playTrack(voice, mAudioTrack);
			}

			// Thread.sleep(50000);
		} catch (Exception ex) {
			try {
				ex.printStackTrace();

			} catch (Exception ex1) {
				ex1.printStackTrace();
			}
		}
	}

	public static void openUDPConnection() {
		// TODO Auto-generated method stub
		try {
			Log.d("client", "Connecting to server");
			socket = new DatagramSocket();

		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	private static void playTrack(byte[] audioData, AudioTrack mAudioTrack) {
		mAudioTrack.write(audioData, 0, 16000);
	}

	private void sendVoiceData() {
		byte data[] = null;
		int read = 0;

		{
			int offset = 0;
			int k = 0;
			StringBuffer buf = new StringBuffer();
			boolean error = false;
			while (isRecording) {
				data = new byte[bufferSize];
				error = true;
				Log.d("client", "reading data " + "count " + k++);
				if (data != null) {
				read = recorder.read(data, offset, bufferSize);
					if(AudioRecord.ERROR_INVALID_OPERATION != read) {
						error = false;
					}
				}
				/*for (int i = 0; i < 100; i++) {
					buf.append(Integer.toHexString(data[i]));
					buf.append(" ");
				}
				Log.d("client", buf.toString());*/
				if (error == false) {
					sendUDPMessage(data, read);
				}
			}

		}
	}

	void sendUDPMessage(byte[] msg, int readByte) {
		try {
			if (msg == null) {
				Log.d("client", "msg is null");
			}
			Set ips = memInfo.keySet();
			Iterator<String> itr = ips.iterator();

			while (itr.hasNext()) {
				InetAddress host = null;
				int port = -1;
				try {
					String str = itr.next();
					host = InetAddress.getByName(str);
					port = memInfo.get(str);
				} catch (UnknownHostException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				DatagramPacket pack = new DatagramPacket(msg, readByte, host,
						port);
				socket.send(pack);
			}

		} catch (IOException ioException) {
			ioException.printStackTrace();
		} catch (Exception ex) {
			Log.d("client", "Server error " + ex.getMessage());
		}
	}

	private void startRecording() {
		recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 16000,
				AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT,
				bufferSize);

		// hardware recording function
		recorder.startRecording();

		isRecording = true;
		recordingThread = new Thread(new Runnable() {

			@Override
			public void run() {
				sendVoiceData();
				Log.d("client", "in write audio");
			}
		}, "AudioRecorder Thread");

		recordingThread.start();
	}

	private void enableButton(int id, boolean isEnable) {
		((Button) findViewById(id)).setEnabled(isEnable);
	}

	private void stopRecording() {
		if (null != recorder) {
			isRecording = false;

			recordingThread.stop();
			recorder.stop();
			recorder.release();
			recorder = null;
			
		}
	}
}
